package com.jie.server.core.runnable;

import com.jie.common.message.entity.Message;
import com.jie.common.ssl.constant.SslConstant;
import com.jie.common.ssl.util.AesUtil;
import com.jie.server.core.constant.ChannelAttachmentStatusConstant;
import com.jie.server.core.entity.ChannelAttachment;
import com.jie.server.core.util.NioUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.LinkedList;

/**
 * 用于处理写的Runnable对象
 * @author XieZhiJie
 * @date 2022/04/22 12:05
 */
public class WriteHandlerRunnable implements Runnable {

    private final Logger logger = LoggerFactory.getLogger(WriteHandlerRunnable.class);

    private final SelectionKey key;

    public WriteHandlerRunnable(SelectionKey key) {
        this.key = key;
    }

    @Override
    public void run() {
        try {
            handleWrite();
        } catch (Exception e) {
            logger.error(e.getMessage());
            NioUtil.closeKeyChannelAndCancel(this.key);
        }
    }

    /**
     * 处理读事件
     * @throws Exception Exception
     */
    private void handleWrite() throws Exception {
        ChannelAttachment channelAttachment = (ChannelAttachment) this.key.attachment();
        SocketChannel socketChannel = (SocketChannel) this.key.channel();
        // 开始操作写队列
        synchronized (channelAttachment.lock) {
            // 正在写
            channelAttachment.lock.status = ChannelAttachmentStatusConstant.WRITING_STATUS;
        }
        while (channelAttachment.writeQueue.size() != 0) {
            Message message = channelAttachment.writeQueue.poll();
            // 加上摘要再加密
            message.setMessageBytes(AesUtil.addDigestAndEncrypt(message.getMessageBytes(), channelAttachment.getAes(), SslConstant.OPEN_SSL));
            NioUtil.writeMessage(socketChannel, channelAttachment.getWriteByteBuffer(), message);
        }
        synchronized (channelAttachment.lock) {
            // 写结束
            if (!channelAttachment.blockQueue.isEmpty()) {
                channelAttachment.writeQueue = channelAttachment.blockQueue;
                channelAttachment.blockQueue = new LinkedList<>();
                channelAttachment.lock.status = ChannelAttachmentStatusConstant.LISTEN_WRITE_STATUS;
                channelAttachment.interestOps(this.key, key.interestOps() | SelectionKey.OP_WRITE);
            } else {
                // 如果没有信息了, 那么设置状态为非写
                channelAttachment.lock.status = ChannelAttachmentStatusConstant.NOT_IN_WRITE_STATUS;
            }
        }
    }

}
